//
//  Downloader.m
//  lib
//

//
#import "Downloader.h"
#import "libNetworkActivityIndicator.h"
#import "libReachability.h"


#define	TIME_OUT_LIMIT_SEC		5.0f		
#ifdef DOWNLOADER_APIREQUEST_TIMEOUT_SECOND
#	undef	TIME_OUT_LIMIT_SEC
#	define	TIME_OUT_LIMIT_SEC	DOWNLOADER_APIREQUEST_TIMEOUT_SECOND
#endif



@implementation libDownloadInfo
@synthesize url_path;
@synthesize save_name;
@synthesize delegate;
@synthesize priority;

//--------------------------------------------------------------------
- (id)init
{
	[super init];
	return self;
}

//--------------------------------------------------------------------
- (id)initWithSet:(NSString*)url_path_arg saveName:(NSString*)save_name_arg delegate:(id)delegate_arg priority:(int)priority_arg
{
	[self set:url_path_arg saveName:save_name_arg delegate:delegate_arg priority:priority_arg];
	
	return self;
}

//--------------------------------------------------------------------
- (void)dealloc
{
	//SAFE_RELEASE(delegate);
	[self reset];
	[super dealloc];
}

//--------------------------------------------------------------------

- (void)set:(NSString*)url_path_arg saveName:(NSString*)save_name_arg delegate:(id)delegate_arg priority:(int)priority_arg
{
	url_path = [[NSString alloc] initWithString:url_path_arg];
	save_name = [[NSString alloc] initWithString:save_name_arg];
	//[delegate_arg retain];
	//[delegate release];
	delegate = delegate_arg;
	priority = priority_arg;
}

//--------------------------------------------------------------------
- (void)reset
{
	delegate = nil;
	
	SAFE_RELEASE(url_path)
	SAFE_RELEASE(save_name)
}

@end


@interface Downloader(private)
- (void)initMember;
- (void)releaseMember;
@end
@implementation Downloader
@synthesize m_StatusCode;
static int					m_couter_memory =0;
//--------------------------------------------------------------------

- (void)initMember
{
	m_UrlConect = nil;
	m_UrlPath = nil;
	m_SaveName = nil;
	m_Data = nil;
	m_IsDownload = NO;
	
	m_pDelegate = nil;
}
//--------------------------------------------------------------------

- (id)init
{
	if( self = [super init] )
	{
		[self initMember];
		m_DownloadArray = [[NSMutableArray array] retain];
		m_couter_memory++;
	}
	return self;
}


//--------------------------------------------------------------------

- (void)releaseMember
{
	SAFE_RELEASE(m_UrlConect)
	SAFE_RELEASE(m_UrlPath)
	SAFE_RELEASE(m_SaveName)
	SAFE_RELEASE(m_Data)
//	free( downloaded_data ); downloaded_data = 0;
//	downloaded_size = 0;
}

//--------------------------------------------------------------------

- (void)dealloc
{
	[self cancel];
	[self releaseMember];
	[self initMember];
	SAFE_RELEASE(m_DownloadArray);
	//SAFE_RELEASE(m_pDelegate);
	m_couter_memory--;
	[super dealloc];
}


//--------------------------------------------------------------------
- (BOOL)isExec
{
	return m_IsDownload;
}

//--------------------------------------------------------------------
//--------------------------------------------------------------------
//	out:
//		DLResponse	: 
//--------------------------------------------------------------------
- (DLResponse)requestDownload:(id)request_obj urlPath:(NSString*)url_path saveName:(NSString*)save_name delegate:(id)delegate
{
	return [self requestDownload:url_path saveName:save_name delegate:delegate priority:DL_PRIORITY_NORMAL];
}
- (DLResponse)requestDownload:(NSString*)url_path saveName:(NSString*)save_name delegate:(id)delegate priority:(int)priority
{
	libDownloadInfo* next = [[[libDownloadInfo alloc] initWithSet:url_path saveName:save_name delegate:delegate priority:priority] autorelease];
	
	if( priority == DL_PRIORITY_TOP )
	{
		[m_DownloadArray insertObject:next atIndex:0];
	}
	else if( priority == DL_PRIORITY_BOTTOM )
	{
		[m_DownloadArray addObject:next];
	}
	else
	{
		int index = 0;
		for( libDownloadInfo* info in m_DownloadArray )
		{
			if( info.priority < priority )
				break;
			index++;
		}
		[m_DownloadArray insertObject:next atIndex:index];
	}
	return DL_RESPONSE_OK;
}

//--------------------------------------------------------------------
- (BOOL)start:(NSString*)url_path saveName:(NSString*)save_name delegate:(id)delegate
{
	if ( ![[libReachability Shared] IsInternetConnect] ) {
		m_StatusCode = 0;
		
		if ( [delegate respondsToSelector:@selector(downloaderError:)] ) {
			[delegate performSelector:@selector(downloaderError:)
						   withObject:save_name
						   afterDelay:0.1];
		}
		return YES;
	}
	
	
	BOOL ret = NO;
	
	if( ![self isExec] )
	{

		NSURL*					url	= [NSURL URLWithString:url_path];
#ifndef __DOWNLOADER_USE_INTERVAL__//-------------------------------------------------------------------------------
		NSMutableURLRequest*	req	= [NSMutableURLRequest requestWithURL:url];
#else//__DOWNLOADER_USE_INTERVAL__
		NSMutableURLRequest*	req	= [NSMutableURLRequest requestWithURL:url
															  cachePolicy:NSURLRequestUseProtocolCachePolicy
														  timeoutInterval:TIME_OUT_LIMIT_SEC];
		DebLog(@"timeout interval = %f", TIME_OUT_LIMIT_SEC);
#endif//__DOWNLOADER_USE_INTERVAL__
		m_UrlConect = [[NSURLConnection connectionWithRequest:req delegate:self] retain];
		if( m_UrlConect )
		{
			[[libNetworkActivityIndicator Shared] setVisible:YES];

			
			m_UrlPath = [url_path retain];
			m_SaveName = [save_name retain];
			//[delegate retain];
			//[m_pDelegate release];
			m_pDelegate = delegate;
			
			
			m_Data = [[NSMutableData alloc] initWithLength:0];
			
			m_StatusCode = 0;
			
			m_IsDownload = YES;
			ret = YES;
		}
	}
	return ret;
}


- (BOOL)startWithRequest:(NSMutableURLRequest*)req saveName:(NSString*)save_name delegate:(id)delegate
{
	if ( ![[libReachability Shared] IsInternetConnect] ) {
		m_StatusCode = 0;
		
		if ( [delegate respondsToSelector:@selector(downloaderError:)] ) {
			[delegate performSelector:@selector(downloaderError:)
						   withObject:save_name
						   afterDelay:0.1];
		}
		return YES;
	}
	
	BOOL ret = NO;
	
	if( ![self isExec] )
	{
		
		m_UrlConect = [[NSURLConnection connectionWithRequest:req delegate:self] retain];
		if( m_UrlConect )
		{
			
			[[libNetworkActivityIndicator Shared] setVisible:YES];
			
			m_UrlPath = [[[req URL] absoluteString]retain];
			m_SaveName = [save_name retain];
			//[delegate retain];
			//[m_pDelegate release];
			m_pDelegate = delegate;
			
			
			m_Data = [[NSMutableData alloc] initWithLength:0];
			
			m_StatusCode = 0;
			
			m_IsDownload = YES;
			ret = YES;
		}
	}
	return ret;
}


- (void)cancel
{
	[self cancel:m_pDelegate];
}
- (void)cancelAll
{
	[self cancel:nil];
}
- (void)cancel:(id)delegate
{
	if( [self isExec] )
	{
		if( m_pDelegate == delegate || delegate == nil )
		{
			[m_UrlConect cancel];
			
			
			[self cancelForDelegate:m_pDelegate];
			
		
			[self releaseMember];
			[self initMember];
		}
	}
	
	
	if([m_DownloadArray count])
	{
		int index = 0;
		while( index < [m_DownloadArray count] )
		{
			libDownloadInfo* next = [m_DownloadArray objectAtIndex:index];
			if( next.delegate == delegate || delegate == nil )
			{
				[self cancelForDelegate:next.delegate];
				[m_DownloadArray removeObjectAtIndex:index];
			}
			else
				index++;
		}
	}
}


- (void)cancelForDelegate:(id)delegate
{
	
	[[libNetworkActivityIndicator Shared] setVisible:NO];
	
	if( delegate )
	{
		
		if( delegate && [delegate respondsToSelector:@selector(downloaderCancel)] )
		{
			[delegate downloaderCancel];
		}
	}
}


- (void)update
{
	if([self isExec] == NO)
	{
		
		if([m_DownloadArray count])
		{
			libDownloadInfo* next = [m_DownloadArray objectAtIndex:0];
			[self start:next.url_path
			   saveName:next.save_name
			   delegate:next.delegate
			 ];
			
			[m_DownloadArray removeObjectAtIndex:0];
			
			m_StatusCode = 0;
		}
	}
}


#pragma mark -
#pragma mark NSURLConnection delegates

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
	[m_Data setLength:0];
	
	
	m_StatusCode = [(NSHTTPURLResponse*)response statusCode];
	DebLog(@"downloader statusCode:%d", m_StatusCode);
	

	if( m_StatusCode >= 400 )
	{
		
		if( m_pDelegate && [m_pDelegate respondsToSelector:@selector(downloaderError:)] )
		{
			[m_pDelegate downloaderError:response.URL.absoluteString];
		}
	}
	
	else if( m_pDelegate && [m_pDelegate respondsToSelector:@selector(downloaderStart:)] )
	{
		[m_pDelegate downloaderStart:m_SaveName];
	}
}


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
	[m_Data appendData:data];

	if ( m_StatusCode < 400 ) {
		
		if( m_pDelegate && [m_pDelegate respondsToSelector:@selector(downloaderConnection:)] )
		{
			if( [m_pDelegate downloaderConnection:data] )
			{
				SAFE_RELEASE(m_Data)
				m_Data = [[NSMutableData alloc] initWithLength:0];
			}
		}
	}
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
	
	[[libNetworkActivityIndicator Shared] setVisible:NO];
	
	
	if( m_pDelegate && [m_pDelegate respondsToSelector:@selector(downloaderError:)] )
	{
		[m_pDelegate downloaderError:m_UrlPath];
	}
	
	[self releaseMember];
	[self initMember];
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
	
	[[libNetworkActivityIndicator Shared] setVisible:NO];
	
	DebLog(@"downloader - finish load:%@(%dBytes)", m_SaveName, m_Data.length);
	
	
	if( m_StatusCode < 400 )
	{
	
		if( m_pDelegate && [m_pDelegate respondsToSelector:@selector(downloaderFinish:saveName:)] )
		{
			[m_pDelegate downloaderFinish:m_Data saveName:m_SaveName];
		}
	}
	
	id  delegate   = m_pDelegate;
	int statusCode = m_StatusCode;
	
	
	[self releaseMember];
	[self initMember];
	
	
	if( statusCode < 400 )
	{
		
		if( delegate && [delegate respondsToSelector:@selector(downloaderFinishAfter)] )
		{
			[delegate downloaderFinishAfter];
		}
	}
}


- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
	return nil;
}

- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response
{
	return	request;
}

//--------------------------------------------------------------------
//--------------------------------------------------------------------
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
}

//--------------------------------------------------------------------
//--------------------------------------------------------------------
- (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
}
/////////////////////////////////////////////////////////////////////////
#pragma mark -

@end
